###########################################################################
#                            TEXTMATE SNIPPETS                            #
###########################################################################

#! header
snippet #! "Shebang header for python scripts" b
#!/usr/bin/env python
# encoding: utf-8
$0
endsnippet

snippet ifmain "ifmain" b
if __name__ == '__main__':
	${1:main()}$0
endsnippet


##########
# COMMON #
##########

# The smart def and smart class snippets use a global option called
# "g:ultisnips_python_style" which, if set to "doxygen" will use doxygen
# style comments in docstrings.

global !p

NORMAL  = 0x1
DOXYGEN = 0x2
SPHINX  = 0x3

SINGLE_QUOTES = 0x1
DOUBLE_QUOTES = 0x2

def get_args(arglist):
	args = [arg.split('=')[0].strip() for arg in arglist.split(',') if arg]
	args = [arg for arg in args if arg and arg != "self"]

	return args


def get_quoting_style(snip):
	style = snip.opt("g:ultisnips_python_quoting_style", "double")
	if style == 'single':
		return SINGLE_QUOTES
	return DOUBLE_QUOTES

def tripple_quotes(snip):
	if get_quoting_style(snip) == SINGLE_QUOTES:
		return "'''"
	return '"""'

def get_style(snip):
	style = snip.opt("g:ultisnips_python_style", "normal")

	if    style == "doxygen": return DOXYGEN
	elif  style == "sphinx": return SPHINX
	else: return NORMAL


def format_arg(arg, style):
	if style == DOXYGEN:
		return "@param %s @todo" % arg
	elif style == SPHINX:
		return ":param %s: @todo" % arg
	elif style == NORMAL:
		return ":%s: @todo" % arg


def format_return(style):
	if style == DOXYGEN:
		return "@return: @todo"
	elif style in (NORMAL, SPHINX):
		return ":returns: @todo"


def write_docstring_args(args, snip):
	if not args:
		snip.rv += ' {0}'.format(tripple_quotes(snip))
		return

	snip.rv += '\n' + snip.mkline('', indent='')

	style = get_style(snip)

	for arg in args:
		snip += format_arg(arg, style)


def write_init_body(args, parents, snip):
	parents = [p.strip() for p in parents.split(",")]
	parents = [p for p in parents if p != 'object']

	for p in parents:
		snip += p + ".__init__(self)"

	if parents:
		snip.rv += '\n' + snip.mkline('', indent='')

	for arg in args:
		snip += "self._%s = %s" % (arg, arg)


def write_slots_args(args, snip):
	args = ['"_%s"' % arg for arg in args]
	snip += '__slots__ = (%s,)' % ', '.join(args)

endglobal

########################################
# Class & Special Method Name Snippets #
########################################

snippet class "class with docstrings" b
class ${1:MyClass}(${2:object}):

	`!p snip.rv = tripple_quotes(snip)`${3:Docstring for $1. }`!p snip.rv = tripple_quotes(snip)`

	def __init__(self$4):
		`!p snip.rv = tripple_quotes(snip)`${5:@todo: to be defined1.}`!p
snip.rv = ""
snip >> 2

args = get_args(t[4])

write_docstring_args(args, snip)
if args:
	snip.rv += '\n' + snip.mkline('', indent='')
	snip += '{0}'.format(tripple_quotes(snip))

write_init_body(args, t[2], snip)
`
		$0
endsnippet


snippet slotclass "class with slots and docstrings" b
class ${1:MyClass}(${2:object}):

	`!p snip.rv = tripple_quotes(snip)`${3:Docstring for $1. }`!p snip.rv = tripple_quotes(snip)`
`!p
snip >> 1
args = get_args(t[4])
write_slots_args(args, snip)
`

	def __init__(self$4):
		`!p snip.rv = tripple_quotes(snip)`${5:@todo: to be defined.}`!p
snip.rv = ""
snip >> 2

args = get_args(t[4])

write_docstring_args(args, snip)
if args:
	snip.rv += '\n' + snip.mkline('', indent='')
	snip += tripple_quotes(snip)

write_init_body(args, t[2], snip)
`
		$0
endsnippet


snippet contain "methods for emulating a container type" b
def __len__(self):
	${1:pass}

def __getitem__(self, key):
	${2:pass}

def __setitem__(self, key, value):
	${3:pass}

def __delitem__(self, key):
	${4:pass}

def __iter__(self):
	${5:pass}

def __reversed__(self):
	${6:pass}

def __contains__(self, item):
	${7:pass}
endsnippet


snippet context "context manager methods" b
def __enter__(self):
	${1:pass}

def __exit__(self, exc_type, exc_value, traceback):
	${2:pass}
endsnippet


snippet attr "methods for customizing attribute access" b
def __getattr__(self, name):
	${1:pass}

def __setattr__(self, name, value):
	${2:pass}

def __delattr__(self, name):
	${3:pass}
endsnippet


snippet desc "methods implementing descriptors" b
def __get__(self, instance, owner):
	${1:pass}

def __set__(self, instance, value):
	${2:pass}

def __delete__(self, instance):
	${3:pass}
endsnippet


snippet cmp "methods implementing rich comparison"
def __eq__(self, other):
	${1:pass}

def __ne__(self, other):
	${2:pass}

def __lt__(self, other):
	${3:pass}

def __le__(self, other):
	${4:pass}

def __gt__(self, other):
	${5:pass}

def __ge__(self, other):
	${6:pass}

def __cmp__(self, other):
	${7:pass}
endsnippet


snippet repr "methods implementing string representation"
def __repr__(self):
	${1:pass}

def __str__(self):
	${2:pass}

def __unicode__(self):
	${3:pass}
endsnippet


# note: reflected operands and augmented arithmeitc assignements have been
# intentionally ommited to reduce verbosity.
snippet numeric "methods for emulating a numeric type" b
def __add__(self, other):
	${1:pass}

def __sub__(self, other):
	${2:pass}

def __mul__(self, other):
	${3:pass}

def __div__(self, other):
	${4:pass}

def __truediv__(self, other):
	${5:pass}

def __floordiv__(self, other):
	${6:pass}


def __mod__(self, other):
	${7:pass}

def __divmod__(self, other):
	${8:pass}

def __pow__(self, other):
	${9:pass}


def __lshift__(self, other):
	${10:pass}

def __rshift__(self, other):
	${11:pass}

def __and__(self, other):
	${12:pass}

def __xor__(self, other):
	${13:pass}

def __or__(self, other):
	${14:pass}


def __neg__(self):
	${15:pass}

def __pos__(self):
	${16:pass}

def __abs__(self):
	${17:pass}

def __invert__(self):
	${18:pass}


def __complex__(self):
	${19:pass}

def __int__(self):
	${20:pass}

def __long__(self):
	${21:pass}

def __float__(self):
	${22:pass}


def __oct__(self):
	${22:pass}

def __hex__(self):
	${23:pass}


def __index__(self):
	${24:pass}

def __coerce__(self, other):
	${25:pass}
endsnippet

snippet def "function with docstrings" b
def ${1:function}(`!p
if snip.indent:
	snip.rv = 'self' + (", " if len(t[2]) else "")`${2:arg1}):
	`!p snip.rv = tripple_quotes(snip)`${4:@todo: Docstring for $1.}`!p
snip.rv = ""
snip >> 1

args = get_args(t[2])
if args:
	write_docstring_args(args, snip)

style = get_style(snip)
snip += format_return(style)
snip.rv += '\n' + snip.mkline('', indent='')
snip += tripple_quotes(snip) `
	${0:pass}
endsnippet


# doesn't expand when there is a word in front
snippet /(^|(?<=\W))\./ "self." r
self.
endsnippet

snippet from "from module import name" b
from ${1:module} import ${2:Stuff}
endsnippet


##############
# PROPERTIES #
##############
snippet roprop "Read Only Property" b
@property
def ${1:name}(self):
	${2:return self._$1}$0
endsnippet

snippet rwprop "Read write property" b
def ${1:name}():
	`!p snip.rv = tripple_quotes(snip) if t[2] else ''
`${2:@todo: Docstring for $1.}`!p
if t[2]:
	snip >> 1

	style = get_style(snip)
	snip.rv += '\n' + snip.mkline('', indent='')
	snip += format_return(style)
	snip.rv += '\n' + snip.mkline('', indent='')
	snip += tripple_quotes(snip)
else:
	snip.rv = ""`
	def fget(self):
		return self._$1$0

	def fset(self, value):
		self._$1 = value
	return locals()

$1 = property(**$1(), doc=$1.__doc__)
endsnippet


####################
# If / Else / Elif #
####################
snippet if "If" b
if ${1:condition}:
	${2:pass}
endsnippet

snippet ife "If / Else" b
if ${1:condition}:
	${2:pass}
else:
	${3:pass}
endsnippet

snippet ifee "If / Elif / Else" b
if ${1:condition}:
	${2:pass}
elif ${3:condition}:
	${4:pass}
else:
	${5:pass}
endsnippet


##########################
# Try / Except / Finally #
##########################
snippet try "Try / Except" b
try:
	${1:pass}
except ${2:Exception}, ${3:e}:
	${4:raise $3}
endsnippet

snippet try "Try / Except / Else" b
try:
	${1:pass}
except ${2:Exception}, ${3:e}:
	${4:raise $3}
else:
	${5:pass}
endsnippet

snippet try "Try / Except / Finally" b
try:
	${1:pass}
except ${2:Exception}, ${3:e}:
	${4:raise $3}
finally:
	${5:pass}
endsnippet

snippet try "Try / Except / Else / Finally" b
try:
	${1:pass}
except${2: ${3:Exception}, ${4:e}}:
	${5:raise}
else:
	${6:pass}
finally:
	${7:pass}
endsnippet


#####################
# Assertions & Tests #
#####################

snippet pdb "Set PDB breakpoint" b
import pdb; pdb.set_trace()
endsnippet

snippet ipdb "Set IPDB breakpoint" b
import ipdb; ipdb.set_trace()
endsnippet

snippet pudb "Set PUDB breakpoint" b
import pudb; pudb.set_trace()
endsnippet

snippet ae "Assert equal" b
self.assertEqual(${1:first},${2:second})
endsnippet

snippet at "Assert True" b
self.assertTrue(${0:exp})
endsnippet

snippet af "Assert False" b
self.assertFalse(${1:expression})
endsnippet

snippet aae "Assert almost equal" b
self.assertAlmostEqual(${1:first},${2:second})
endsnippet

snippet ar "Assert raises" b
self.assertRaises(${1:exception}, ${2:func}${3/.+/, /}${3:arguments})
endsnippet


snippet testcase "pyunit testcase" b
class Test${1:Class}(${2:unittest.TestCase}):

	`!p snip.rv = tripple_quotes(snip)`${3:Test case docstring.}`!p snip.rv = tripple_quotes(snip)`

	def setUp(self):
		${4:pass}

	def tearDown(self):
		${5:pass}

	def test_${6:name}(self):
		${7:pass}
endsnippet

# vim:ft=snippets:
